package com.xy.smartplatfrom.service.impl;

import com.xy.smartplatfrom.cache.DefaultRoleCache;
import com.xy.smartplatfrom.cache.RoleCache;
import com.xy.smartplatfrom.exceptions.MyBaseException;
import com.xy.smartplatfrom.exceptions.QueayDataException;
import com.xy.smartplatfrom.exceptions.ResultCode;
import com.xy.smartplatfrom.mapper.UserMapper;
import com.xy.smartplatfrom.pojo.CheckType;
import com.xy.smartplatfrom.pojo.DefaultRole;
import com.xy.smartplatfrom.pojo.Role;
import com.xy.smartplatfrom.pojo.User;
import com.xy.smartplatfrom.service.UserService;
import com.xy.smartplatfrom.utils.MD5utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * projectName:smartplatfrom
 * author:xiaoyang
 * time:2021/12/27 22:06
 * description:
 */
@Service
@Transactional//事务控制
public class UserServiceImpl implements UserService {
    private UserMapper userMapper;

   private DefaultRoleCache defaultRoleCache;

   private RoleCache roleCache;

   private ApplicationContext context;

   @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    @Autowired
    public void setDefaultRoleCache(DefaultRoleCache defaultRoleCache) {
        this.defaultRoleCache = defaultRoleCache;
    }
    @Autowired
    public void setRoleCache(RoleCache roleCache) {
        this.roleCache = roleCache;
    }

    @Autowired
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 添加用户
     * @param user
     */
    @Override
    public void addUser(User user) {



    //一系列逻辑判断等等

//        if(StringUtils.hasText(user.getusername)){
//         //使用自定义异常
//            throw new MyBaseException("传递的用户名时空的", ResultCode.USERNAME_NULL);
//        }
        Assert.isTrue(!user.isEmpty(CheckType.ADD),()->{
            throw new MyBaseException("必须传递的数据不完整，请检查", ResultCode.USERNAME_NULL);
        });



        //判断数据是否存在
        //根据 用户名 手机号 邮箱 查询用户
        List currentUser = userMapper.selectByUserNameOrPhoneOrEmail(user.getUsername(), user.getPhone(), user.getEmail());

        //上面对象必须是空的 不为空说明数据已经存在

        //断言
        Assert.isTrue(currentUser.size()==0,()->{
            throw new MyBaseException("账户已存在", ResultCode.DATA_ALREADY_EXIST);
        });


        //我们已经能得知的异常能提前处理的就必须要提前处理
        //前端所有的数据都不可信  前的的所有校验都是无效校验 前端校验属于可修改操作  服务端必须做校验

        //非加密算法
        //处理密码 将密码改成md5值
        String password = user.getPassword();//传递的密码
//        String passwordMD5 = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));//将指定的数据转为md5值
      //如果简单这样计算md5 那么相同密码会得到相同值
        //所有我们需要为自己带盐
        //生产随机字符串 作为盐
        //程序中无真正随机数
        //尽量获取一个随机内容？ 避免出现重复内容
        //sessionid 必须不重复  熵池  系统噪声
        String salt = MD5utils.getRandomString(15);//生产一个长度为15的盐
      //拼接在什么位置不重要 要求这里怎么拼  后边计算也怎么拼
        String md5 = MD5utils.getMd5(password, salt, 1024);
        user.setPassword(md5);
        user.setPwdSalt(salt);
        user.setCreateTime(new Date());
        user.setCreateBy(user.getUsername());


        //数据库不支持高并发   不建议 全抛异常
        //查询了默认的角色id
        //****  这个用户的默认角色id  几乎不会变化 每次注册和添加什么数据得到的结果总是一样  没必要总是查询数据库
//        Long roleId = defaultRoleMapper.selectRoleIdByType("user");
//        //根据角色id查询到了角色信息
//        Role role = roleMapper.selectRoleById(roleId);
        DefaultRole defaultRole = defaultRoleCache.getValue("user");
        Role role = roleCache.getValue(defaultRole.getRoleId());

        //设置用户标识
        user.setRemark(role.getRemark());
        userMapper.addUser(user);



        //用户的角色信息没有保存
    }

    @Override
    public User login(String username, String password) {
        //我们判断的标准是和用户的数据进行比较  一致就通过
        //查询数据库    用什么条件查询   只能用账号查询     账号有唯一索引 密码没有
      Assert.isTrue(StringUtils.hasText(username)&&StringUtils.hasText(password),()->{

          throw new QueayDataException("账号和密码错误",ResultCode.USERNAME_PASSWORD_ERROR);
      });

        User user = userMapper.selectUserByUserName(username);
       //只要查询不到就一定是账号错误
        Assert.notNull(user,()->{
            throw new QueayDataException("账号和密码错误",ResultCode.USERNAME_PASSWORD_ERROR);
        });
      //查到结果下一步就要比较密码
        //但是用户传递的密码是明文  数据库中的是md5值  几乎是失败的
        //因为md5是不可逆的  所有我们可以把用户传递的密码转城md5值 然后进行比较 但是传递的时候需要盐
        //盐在用户数据中 我们需要获取 然后用一开始注册时候生产的md5操作再操作一遍
        String pwdSalt = user.getPwdSalt();
        String comMd5 = MD5utils.getMd5(password, pwdSalt, 1024);
       Assert.isTrue(comMd5.equalsIgnoreCase(user.getPassword()),()->{
           throw new QueayDataException("账号和密码错误",ResultCode.USERNAME_PASSWORD_ERROR);
       });
        //说明用户传递的账号和密码是对的
        user.setPassword(null);
        user.setPwdSalt(null);
        //发送事件  更新用户的一些登录后的数据
//        context.publishEvent(new UserLoginEvent());
       return user;
    }

    @Override
    public int updateUserLogin(User user) {
        //判断时间   可以不用判断  因为这个数据不是用户传递的 是我们自己生产的 我们只要确保一定生产就行
        userMapper.upDateUserLogin(user);
        return 0;
    }
}
